package com.ruoyi.framework.propertySourcesEnc;

import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.ConfigurablePropertyResolver;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Setter
@Getter
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class EncryptionAwarePropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {

    private Environment environment;

    private EncryptionAwareService encryptionAwareService;

    public EncryptionAwarePropertySourcesPlaceholderConfigurer(EncryptionAwareService encryptionAwareService) {
        this.encryptionAwareService = encryptionAwareService;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, ConfigurablePropertyResolver propertyResolver) throws BeansException {
        MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
        EncryptionAwarePropertySourcesPropertyResolver.InnerPropertySource embeddedPropertySource = new EncryptionAwarePropertySourcesPropertyResolver.InnerPropertySource("embeddedPropertySource", new HashMap<>());
        embeddedPropertySource.setEncryptionAwareService(encryptionAwareService);

        Map<String, PropertySource<?>> propertySourceMap = propertySources.stream()//
                .map(propertySource -> {//
                    if (propertySource.getSource() instanceof Map) {//
                        EncryptionAwarePropertySourcesPropertyResolver.InnerPropertySource innerPropertySource = new EncryptionAwarePropertySourcesPropertyResolver.InnerPropertySource(propertySource.getName(), (Map<String, Object>) propertySource.getSource());
                        innerPropertySource.setEncryptionAwareService(encryptionAwareService);
                        Map<String, Object> source = innerPropertySource.getSource();
                        List<String> passwordKeys = source.keySet().stream().filter(x -> x.contains("password")).collect(Collectors.toList());
                        passwordKeys.forEach(key -> {
                            Object value = innerPropertySource.getProperty(key);
                            embeddedPropertySource.getSource().put(key, value);
                        });
                        return innerPropertySource;//
                    }
                    return propertySource;
                }).collect(Collectors.toMap(PropertySource::getName, Function.identity()));
//        propertySources.stream().forEach(propertySource -> propertySources.replace(propertySource.getName(), propertySourceMap.get(propertySource.getName())));
        propertySources.addFirst(embeddedPropertySource);
        super.setPropertySources(propertySources);
        super.processProperties(beanFactoryToProcess, new EncryptionAwarePropertySourcesPropertyResolver(propertySources, encryptionAwareService));
    }


}